/*
 * @(#)XfvhdlEntitiesFile.java        3.0                     2004/09/14
 *
 * This file is part of Xfuzzy 3.0, a design environment for fuzzy logic
 * based systems.
 *
 * (c) 2000 IMSE-CNM. The authors may be contacted by the email address:
 *                    xfuzzy-team@imse.cnm.es
 *
 * Xfuzzy is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * Xfuzzy is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */

package xfuzzy.xfvhdl;

/**
* Clase que genera el fichero de entidades Entities.vhdl.
* @author Jos� Mar�a �vila Maireles, <b>e-mail</b>: josavimai@alum.us.es
* @version 3.0
*/
public class XfvhdlEntitiesFile {

   private XfvhdlPrjFile prjFile; // Se usa para crear el archivo .prj

   //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
   //			  CONSTRUCTOR DE LA CLASE				         
   //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// 

   /** Constructor de la clase.
    */
   XfvhdlEntitiesFile(XfvhdlPrjFile pF) {
      prjFile = pF;
   }

   //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
   //			  M�TO_DOS P�BLICOS DE LA CLASE				        
   //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

   /**
   * M�todo que crea la cadena que ser� escrita en fichero Entities.vhdl.
   * @return Devuelve la cadena que ser� escrita en fichero Entities.vhdl.
   */
   public String createEntitiesSource(XfvhdlIDefuzzification defuzzification) {

      XfvhdlHeadFile head =
         new XfvhdlHeadFile(
            XfvhdlProperties.fileDir,
            XfvhdlProperties.outputFile + "Entities.vhdl",
            XfvhdlProperties.ficheroXFL);

      String code = head.getHead();

      code
         += "\n--***********************************************************************--\n"
         + "--                                                                       --\n"
         + "--   DESCRIPTION: This file contains the entity declaration for all the  --\n"
         + "--                components of the fuzzy controller.                    --\n"
         + "--                                                                       --\n"
         + "---------------------------------------------------------------------------\n"
         + "--                                                                       --\n"
         + "--   AUTHOR:      Jose Maria Avila Maireles                              --\n"
         + "--                                                                       --\n"
         + "--   VERSION:     Xfvhdl  ver0.1                          October 2003   --\n"
         + "--                                                                       --\n"
         + "--***********************************************************************--\n"
         + "\n"
         + "\n"
         + "\n"
         + "library IEEE;\n"
         + "use IEEE.std_logic_1164.all;\n"
         + "use IEEE.std_logic_arith.all;\n"
         + "\n"
         + "use WORK.Constants.all;\n"
         + "\n"
         + "\n"
         + "---------------------------------------------------------------------------\n"
         + "--                           Entity description                          --\n"
         + "---------------------------------------------------------------------------\n"
         + "\n"
         + "package Entities is\n\n";

      if (XfvhdlProperties.calcArithmetic == false) {
         code = code + "component Control1_nc\n";

         // A�adimos el componente al fichero .prj
         String hola =
            new String(
               ""
                  + XfvhdlProperties.libraryDirectory
                  + XfvhdlProperties.fileSeparator
                  + "Control1_nc.vhd");
         prjFile.addFile(hola);

         code += "\tport(\tclk\t\t\t: in std_logic;\n"
            + "\t\treset\t\t\t: in std_logic;\n"
            + "\n"
            + "\t\tme1\t\t\t: out std_logic;\n"
            + "\t\tme2\t\t\t: out std_logic;\n"
            + "\t\tpipeline\t\t: out std_logic;\n"
            + "\t\tclear_almacen\t: out std_logic;\n"
            + "\t\tacumulacion\t\t: out std_logic;\n"
            + "\t\tdir2\t\t\t: out std_logic_vector(entradas downto 1));\n"
            + "end component;\n\n";

         // Lo siguiente a escribir en el fichero depende de la memoria
         // donde se valla a implementar el sistema.
         if (XfvhdlProperties.memoryType.equals((String) "ROM")
            || XfvhdlProperties.memoryType.equals(
               (String) "Combinational Logic")) {
            for (int cont = 1;
               cont <= XfvhdlProperties.entradas;
               cont++) {
               code =
                  code
                     + "component AntecedentMem_"
                     + cont
                     + "\n"
                     + "\tport(\taddr\t\t\t: "
                     + "in std_logic_vector(N-1 downto 0);\n"
                     + "\t\tme\t\t\t: in std_logic;\n"
                     + "\n"
                     + "\t\tdo\t\t\t: "
                     + "out std_logic_vector(M-1 downto 0));\n"
                     + "end component;\n\n";
            }
         } else {
            code = code + "component Antecedent_RAM\n";

            // A�adimos el componente al fichero .prj
            prjFile.addFile(
               XfvhdlProperties.libraryDirectory
                  + XfvhdlProperties.fileSeparator
                  + "Antecedent_RAM.vhd");

            code += "\tport(\tclk\t\t\t: in std_logic;\n"
               + "\t\twe\t\t\t: in std_logic;\n"
               + "\t\taddr\t\t\t: in std_logic_vector(N-1 downto 0);\n"
               + "\t\tdi\t\t\t: in std_logic_vector(M-1 downto 0);\n"
               + "\n"
               + "\t\tdo\t\t\t: out std_logic_vector(M-1 downto 0));\n"
               + "end component;\n\n";
         }
      } else {
         code = code + "component Control2_nc\n";

         // A�adimos el componente al fichero .prj
         prjFile.addFile(
            XfvhdlProperties.libraryDirectory
               + XfvhdlProperties.fileSeparator
               + "Control2_nc.vhd");

         code += "\tport(\tclk\t\t\t: in std_logic;\n"
            + "\t\treset\t\t\t: in std_logic;\n"
            + "\n"
            + "\t\tme1\t\t\t: out std_logic;\n"
            + "\t\tme2\t\t\t: out std_logic;\n"
            + "\t\tpipeline\t\t: out std_logic;\n"
            + "\t\tclear_almacen\t: out std_logic;\n"
            + "\t\tacumulacion\t\t: out std_logic;\n"
            + "\t\tdir2\t\t\t: "
            + "out std_logic_vector(entradas downto 1);\n"
            + "\t\taddr_ant\t\t: "
            + "out std_logic_vector(dir_ant downto 1));\n"
            + "end component;\n"
            + "\n"
            + "component Arithmetic\n";

         // A�adimos el componente al fichero .prj
         prjFile.addFile(
            XfvhdlProperties.libraryDirectory
               + XfvhdlProperties.fileSeparator
               + "Arithmetic.vhd");

         code += "\tport(\tclk\t\t\t: in std_logic;\n"
            + "\t\tx\t\t\t: in std_logic_vector(N downto 1);\n"
            + "\t\tpunto\t\t\t: in std_logic_vector(N downto 1);\n"
            + "\t\tpendiente\t\t: in std_logic_vector(P downto 1);\n"
            + "\t\tpipeline\t\t: in std_logic;\n"
            + "\t\taddr_ant\t\t: "
            + "in std_logic_vector(bits_etiq downto 1);\n"
            + "\n"
            + "\t\tgrado1\t\t: out std_logic_vector(grad downto 1);\n"
            + "\t\tgrado2\t\t: out std_logic_vector(grad downto 1);\n"
            + "\t\tnumfp\t\t\t: "
            + "out std_logic_vector(bits_etiq downto 1));\n"
            + "end component;\n"
            + "\n";

         // Lo siguiente a escribir en el fichero depende de la memoria
         // donde se valla a implementar el sistema.
         if (XfvhdlProperties.memoryType.equals((String) "ROM")
            || XfvhdlProperties.memoryType.equals(
               (String) "Combinational Logic")) {
            code += "component ArithCalcMem\n"
               + "\tport(\taddr\t\t\t: "
               + "in std_logic_vector(bits_etiq-1 downto 0);\n"
               + "\t\tme\t\t\t: in std_logic;\n"
               + "\n"
               + "\t\tdo\t\t\t: out std_logic_vector(M-1 downto 0));\n"
               + "end component;\n\n";
         } else {
            code = code + "component ArithCalc_RAM\n";

            // A�adimos el componente al fichero .prj
            prjFile.addFile(
               XfvhdlProperties.libraryDirectory
                  + XfvhdlProperties.fileSeparator
                  + "ArithCalc_RAM.vhd");

            code += "\tport(\tclk\t\t\t: in std_logic;\n"
               + "\t\twe\t\t\t: in std_logic;\n"
               + "\t\taddr\t\t\t: "
               + "in std_logic_vector(bits_etiq-1 downto 0);\n"
               + "\t\tdi\t\t\t: in std_logic_vector(M-1 downto 0);\n"
               + "\n"
               + "\t\tdo\t\t\t: out std_logic_vector(M-1 downto 0));\n"
               + "end component;\n\n";
         }
      }

      // Lo siguiente a escribir en el fichero depende de la memoria
      // donde se valla a implementar el sistema.
      if (XfvhdlProperties.memoryType.equals((String) "ROM")
         || XfvhdlProperties.memoryType.equals(
            (String) "Combinational Logic")) {
         code =
            code
               + "component RulesMem\n"
               + "\tport(\taddr\t\t\t: "
               + "in std_logic_vector(dir_regl downto 1);\n"
               + "\t\tme\t\t\t: in std_logic;\n"
               + "\n"
               + "\t\tdo\t\t\t: "
               + "out std_logic_vector(w_reglas downto 1));\n"
               + "end component;\n"
               + "\n";
      } else {
         code = code + "component RulesMem_RAM\n";

         // A�adimos el componente al fichero .prj
         prjFile.addFile(
            XfvhdlProperties.libraryDirectory
               + XfvhdlProperties.fileSeparator
               + "RulesMem_RAM.vhd");

         code += "\tport(\tclk\t\t\t: in std_logic;\n"
            + "\t\twe\t\t\t: in std_logic;\n"
            + "\t\taddr\t\t\t: "
            + "in std_logic_vector(dir_regl-1 downto 0);\n"
            + "\t\tdi\t\t\t: "
            + "in std_logic_vector(w_reglas-1 downto 0);\n"
            + "\n"
            + "\t\tdo\t\t\t: "
            + "out std_logic_vector(w_reglas-1 downto 0));\n"
            + "end component;\n\n";
      }

      code += "component MF_Grade\n";

      // A�adimos el componente al fichero .prj
      prjFile.addFile(
         XfvhdlProperties.libraryDirectory
            + XfvhdlProperties.fileSeparator
            + "MF_Grade.vhd");

      code += "\tport(\tgrado1\t\t: "
         + "in std_logic_vector(grad downto 1);\n"
         + "\t\tgrado2\t\t: in std_logic_vector(grad downto 1);\n"
         + "\t\tnumfp\t\t\t: in std_logic_vector(bits_etiq downto 1);\n"
         + "\t\tentr_conta\t\t: in std_logic;\n"
         + "\n"
         + "\t\tetiqueta\t\t: "
         + "out std_logic_vector(bits_etiq downto 1);\n"
         + "\t\tgrado\t\t\t: out std_logic_vector(grad downto 1));\n"
         + "end component;\n"
         + "\n";

      // Aqui se introduce la operaci�n AND, que ser� el producto o
      // el m�nimo (por defecto)
      if (XfvhdlProperties.operationAnd.equalsIgnoreCase("prod")) {
         code += "component Product\n";

         // A�adimos el componente al fichero .prj
         prjFile.addFile(
            XfvhdlProperties.libraryDirectory
               + XfvhdlProperties.fileSeparator
               + "Product.vhd");

         code += "\tport(\tentrada\t\t: "
            + "in std_logic_vector((grad * entradas) downto 1);\n"
            + "\n"
            + "\t\tsalida\t\t: out std_logic_vector(grad downto 1));\n"
            + "end component;\n\n";
      } else {
         code += "component Minimum\n";

         // A�adimos el componente al fichero .prj
         prjFile.addFile(
            XfvhdlProperties.libraryDirectory
               + XfvhdlProperties.fileSeparator
               + "Minimum.vhd");

         code += "\tport(\tentrada\t\t: "
            + "in std_logic_vector((grad * entradas) downto 1);\n"
            + "\n"
            + "\t\tsalida\t\t: out std_logic_vector(grad downto 1));\n"
            + "end component;\n\n";
      }

      // A�adimos a code las entidades que dependen del m�todo de 
      // defuzzificaci�n:	
      String tmp = new String();
      tmp = defuzzification.generateEntities();
      code = code + tmp;

      // A�adimos el componente que depende del defuzzificador al 
      // fichero .prj
      prjFile.addFile(
         XfvhdlProperties.libraryDirectory
            + XfvhdlProperties.fileSeparator
            + defuzzification.generatePrjFile());

      code = code + "\n" + "component Division\n";

      // A�adimos el componente al fichero .prj
      prjFile.addFile(
         XfvhdlProperties.libraryDirectory
            + XfvhdlProperties.fileSeparator
            + "Division.vhd");

      code += "\tport(\tdividendo\t\t: "
         + "in std_logic_vector(D downto 1);\n"
         + "\t\tdivisor\t\t: in std_logic_vector(DR downto 1);\n"
         + "\t\tpipeline\t\t: in std_logic;\n"
         + "\t\tclk\t\t\t: in std_logic;\n"
         + "\n"
         + "\t\tcociente\t\t: out std_logic_vector((D - DR) downto 1);\n"
         + "\t\tsali_valid\t\t: out std_logic);\n"
         + "end component;\n\n"
         + "end Entities;";

      return code;
   }

} // Fin de la clase
